﻿using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Editor.OptionsExtensionMethods;
using System;

namespace Language.Intellisense.SmartIndent
{
    static internal class Utility
    {
        #region Types

        internal struct IndentationAnalysis
        {
            #region Private Data

            private int _indentSize;
            private int _tabSize;
            private string _text;
            private bool _indentWithSpaces;

            #endregion Private Data

            #region C-Tor

            public IndentationAnalysis( int indentSize, int tabSize, bool indentWithSpaces, string text )
            {
                _indentSize = indentSize;
                _tabSize = tabSize;
                _text = text;
                _indentWithSpaces = indentWithSpaces;
            }

            #endregion C-Tor

            #region Public Properties

            public int Length => CountIndentation( _text );
            public int IncreasedLength => Length + _tabSize;
            public int DecreasedLength => Math.Max( 0, Length - _tabSize );

            public string Text => _text;
            public string IncreasedText => IndentText( IncreasedLength, Text );
            public string DecreasedText => IndentText( DecreasedLength, Text );

            #endregion Public Properties

            #region Private Methods

            private int CountIndentation( string text )
            {
                int size = 0;

                foreach ( char c in text )
                {
                    switch ( c )
                    {
                        case ' ':
                            ++size;
                            break;

                        case '\t':
                            // Remove any trailing spaces that do not add up to a full tab
                            size = ( ( size / _tabSize ) * _tabSize ) + _tabSize;
                            break;

                        default:
                            return size;
                    }
                }

                return size;
            }

            private string IndentText( int length, string text )
            {
                text = text.TrimStart( ' ', '\t' );

                string indentation = _indentWithSpaces ? new string( ' ', length ) : new string( '\t', length / _tabSize );

                return indentation + text;
            }

            #endregion Private Methods
        }

        #endregion Types

        #region Public Methods

        public static IndentationAnalysis AnalyseIndentation( this ITextView textView, ITextSnapshotLine line )
        {
            string text = line.GetText();

            int indentSize = textView.Options.GetIndentSize();
            int tabSize = textView.Options.GetTabSize();
            bool indentWithSpaces = textView.Options.IsConvertTabsToSpacesEnabled();

            return new IndentationAnalysis( indentSize, tabSize, indentWithSpaces, text );
        }

        public static void ReformatIndentationAtCaret( this ITextView textView )
        {
            int caretPosition = textView.Caret.Position.BufferPosition.Position;
            ITextSnapshotLine line = textView.TextSnapshot.GetLineFromPosition( caretPosition );

            string text = line.GetText();

            int bracePosition;
            if ( !FindCloseBrace( text, out bracePosition ) )
                return;

            IndentationAnalysis indentation = AnalyseIndentation( textView, line );
            textView.TextBuffer.Replace( line.Extent, indentation.DecreasedText );
        }

        #endregion Public Methods

        #region Private Methods

        static bool FindCloseBrace( string text, out int position )
        {
            for ( int i = 0; i < text.Length; ++i )
            {
                switch ( text[ i ] )
                {
                    case ' ':
                    case '\t':
                        break;

                    case '}':
                        position = i;
                        return true;

                    default:
                        System.Diagnostics.Debug.Print( $"SmartIndent.Utility, Found non brace char: '{text[ i ]}'" );
                        position = 0;
                        return false;
                }
            }

            System.Diagnostics.Debug.Print( $"SmartIndent.Utility, No brace on line, must be all whitespace or empty: '{text}'" );
            position = 0;
            return false;
        }

        #endregion Private Methods
    }
}
